﻿// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

namespace Neto.Core.CoreServices;

public class PermissionService(
    ISqlSugarClient db
) : IPermissionService, ITransient
{
    /// <summary>
    /// 验证权限
    /// </summary>
    /// <param name="controller"></param>
    /// <param name="action"></param>
    /// <param name="area">区域，默认HtAdmin，如果是API，默认就是 API</param>
    /// <returns></returns>
    public async Task<bool> IsJwtAuthorize(string controller, string action, string area)
    {
        var userid = App.HttpContext.GetLoginUserId<long>();
        if (userid <= 0) return false; //获取到用户ID小于等于0
        var user = await db.Queryable<SysUser>().FirstAsync(o => o.Id == userid);
        if (user == null)
        {
            return false;
        }
        else if (user.IsEnable == false)
        {
            //登出 账号失效
            return false; //用户没启用，没有权限
        }

        //administrator 与developer 不验证权限
        //if (user.Account.ToLower().Trim() == "administrator".ToLower().Trim() || user.Account.ToLower().Trim() == "developer".ToLower().Trim())
        if (user.UserType is UserType.超级管理员 or UserType.系统维护) return true;

        var isLoginOnly = await db.Queryable<SysMenu>()
            .Where(o => o.IsLoginOnly && o.Area.Equals(area, StringComparison.CurrentCultureIgnoreCase) &&
                        o.Controller.Equals(controller, StringComparison.CurrentCultureIgnoreCase) &&
                        o.Action.Equals(action, StringComparison.CurrentCultureIgnoreCase))
            .AnyAsync();
        if (isLoginOnly)
        {
            return true;// 是否只验证登录（为true表示只验证用户是否登陆，不验证权限）
        }

        // var menus = await GetMenusByUserId(user.Id, area);


        var menuQueryable = db.Queryable<SysMenu, SysRoleMenu, SysRole, SysUserRole, SysUser>((m, rm, r, ur, u) =>
            new JoinQueryInfos(
                JoinType.Left, m.Id == rm.MenuId,
                JoinType.Left, rm.RoleId == r.Id,
                JoinType.Left, r.Id == ur.RoleId,
                JoinType.Left, ur.UserId == u.Id
            ));
        menuQueryable = menuQueryable.Where((m, rm, r, ur, u) => m.Area == area && m.IsEnable == true);
        menuQueryable = menuQueryable.Where((m, rm, r, ur, u) => m.Controller == controller);
        //menuQueryable = menuQueryable.Where((m, rm, r, ur, u) => m.Action == action);
        menuQueryable = menuQueryable.Where((m, rm, r, ur, u) => m.Actions.Contains(action));

        var menuItems = await menuQueryable
            .Select((m, rm, r, ur, u) => new
            {
                m.Id,
                m.Controller,
                m.Action,
                m.Area,
                m.Actions
            })
            .ToListAsync();

        var isAuth = false;
        //使用遍历的方式，严格匹配
        foreach (var menuItem in menuItems)
        {
            isAuth = menuItem.Actions.Split(',').Any(a => a.Trim() == action);
            if (isAuth) break; //找到一个就返回true
        }

        return isAuth;
    }

    /// <summary>
    /// 获取登陆的管理员用户
    /// </summary>
    /// <returns></returns>
    private async Task<SysUser> GetLoginAdminUser()
    {
        var userid = App.HttpContext.GetLoginUserId<long>();
        return await db.GetFirstAsync<SysUser>(o => o.Id == userid);
    }

    /// <summary>
    /// 是否开发人员
    /// </summary>
    /// <returns></returns>
    public async Task<bool> IsDeveloper()
    {
        var loginuser = await GetLoginAdminUser();
        if (loginuser.UserType == UserType.系统维护) return true;
        return false;
    }
}